Age Owner TLA Line data Source code
1 : /* -------------------------------------------------------------------------
2 : *
3 : * pgstat_xact.c
4 : * Transactional integration for the cumulative statistics system.
5 : *
6 : * Copyright (c) 2001-2023, PostgreSQL Global Development Group
7 : *
8 : * IDENTIFICATION
9 : * src/backend/utils/activity/pgstat_xact.c
10 : * -------------------------------------------------------------------------
11 : */
12 :
13 : #include "postgres.h"
14 :
15 : #include "access/transam.h"
16 : #include "access/xact.h"
17 : #include "pgstat.h"
18 : #include "utils/memutils.h"
19 : #include "utils/pgstat_internal.h"
20 :
21 :
22 : typedef struct PgStat_PendingDroppedStatsItem
23 : {
24 : xl_xact_stats_item item;
25 : bool is_create;
26 : dlist_node node;
27 : } PgStat_PendingDroppedStatsItem;
28 :
29 :
30 : static void AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit);
31 : static void AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
32 : bool isCommit, int nestDepth);
33 :
34 : static PgStat_SubXactStatus *pgStatXactStack = NULL;
35 :
36 :
37 : /*
38 : * Called from access/transam/xact.c at top-level transaction commit/abort.
39 : */
40 : void
368 andres 41 CBC 486200 : AtEOXact_PgStat(bool isCommit, bool parallel)
42 : {
43 : PgStat_SubXactStatus *xact_state;
44 :
45 486200 : AtEOXact_PgStat_Database(isCommit, parallel);
46 :
47 : /* handle transactional stats information */
48 486200 : xact_state = pgStatXactStack;
49 486200 : if (xact_state != NULL)
50 : {
51 293944 : Assert(xact_state->nest_level == 1);
52 293944 : Assert(xact_state->prev == NULL);
53 :
54 293944 : AtEOXact_PgStat_Relations(xact_state, isCommit);
55 293944 : AtEOXact_PgStat_DroppedStats(xact_state, isCommit);
56 : }
57 486200 : pgStatXactStack = NULL;
58 :
59 : /* Make sure any stats snapshot is thrown away */
60 486200 : pgstat_clear_snapshot();
61 486200 : }
62 :
63 : /*
64 : * When committing, drop stats for objects dropped in the transaction. When
65 : * aborting, drop stats for objects created in the transaction.
66 : */
67 : static void
68 293944 : AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
69 : {
70 : dlist_mutable_iter iter;
71 293944 : int not_freed_count = 0;
72 :
158 drowley 73 GNC 293944 : if (dclist_count(&xact_state->pending_drops) == 0)
368 andres 74 CBC 214415 : return;
368 andres 75 ECB :
158 drowley 76 GNC 287733 : dclist_foreach_modify(iter, &xact_state->pending_drops)
368 andres 77 ECB : {
368 andres 78 GIC 208204 : PgStat_PendingDroppedStatsItem *pending =
158 drowley 79 GNC 208204 : dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
368 andres 80 GIC 208204 : xl_xact_stats_item *it = &pending->item;
81 :
82 208204 : if (isCommit && !pending->is_create)
83 : {
84 : /*
368 andres 85 ECB : * Transaction that dropped an object committed. Drop the stats
86 : * too.
87 : */
368 andres 88 CBC 32137 : if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
368 andres 89 GIC 4575 : not_freed_count++;
90 : }
91 176067 : else if (!isCommit && pending->is_create)
92 : {
93 : /*
368 andres 94 ECB : * Transaction that created an object aborted. Drop the stats
368 andres 95 EUB : * associated with the object.
96 : */
368 andres 97 GIC 1683 : if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
368 andres 98 LBC 0 : not_freed_count++;
368 andres 99 ECB : }
100 :
158 drowley 101 GNC 208204 : dclist_delete_from(&xact_state->pending_drops, &pending->node);
368 andres 102 CBC 208204 : pfree(pending);
103 : }
104 :
368 andres 105 GIC 79529 : if (not_freed_count > 0)
106 1766 : pgstat_request_entry_refs_gc();
107 : }
108 :
368 andres 109 ECB : /*
110 : * Called from access/transam/xact.c at subtransaction commit/abort.
111 : */
112 : void
368 andres 113 GIC 8797 : AtEOSubXact_PgStat(bool isCommit, int nestDepth)
368 andres 114 ECB : {
115 : PgStat_SubXactStatus *xact_state;
116 :
117 : /* merge the sub-transaction's transactional stats into the parent */
368 andres 118 GIC 8797 : xact_state = pgStatXactStack;
368 andres 119 CBC 8797 : if (xact_state != NULL &&
368 andres 120 GIC 3746 : xact_state->nest_level >= nestDepth)
368 andres 121 ECB : {
122 : /* delink xact_state from stack immediately to simplify reuse case */
368 andres 123 GIC 3336 : pgStatXactStack = xact_state->prev;
368 andres 124 ECB :
368 andres 125 GIC 3336 : AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
368 andres 126 CBC 3336 : AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
127 :
368 andres 128 GIC 3336 : pfree(xact_state);
129 : }
130 8797 : }
131 :
368 andres 132 ECB : /*
133 : * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
134 : */
135 : static void
368 andres 136 GIC 3336 : AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
368 andres 137 ECB : bool isCommit, int nestDepth)
138 : {
139 : PgStat_SubXactStatus *parent_xact_state;
140 : dlist_mutable_iter iter;
368 andres 141 GIC 3336 : int not_freed_count = 0;
368 andres 142 ECB :
158 drowley 143 GNC 3336 : if (dclist_count(&xact_state->pending_drops) == 0)
368 andres 144 CBC 3267 : return;
145 :
146 69 : parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
368 andres 147 ECB :
158 drowley 148 GNC 202 : dclist_foreach_modify(iter, &xact_state->pending_drops)
149 : {
368 andres 150 CBC 133 : PgStat_PendingDroppedStatsItem *pending =
158 drowley 151 GNC 133 : dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
368 andres 152 CBC 133 : xl_xact_stats_item *it = &pending->item;
153 :
158 drowley 154 GNC 133 : dclist_delete_from(&xact_state->pending_drops, &pending->node);
155 :
368 andres 156 GIC 133 : if (!isCommit && pending->is_create)
368 andres 157 ECB : {
368 andres 158 EUB : /*
368 andres 159 ECB : * Subtransaction creating a new stats object aborted. Drop the
160 : * stats object.
161 : */
368 andres 162 GIC 63 : if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
368 andres 163 UIC 0 : not_freed_count++;
368 andres 164 GIC 63 : pfree(pending);
165 : }
166 70 : else if (isCommit)
167 : {
368 andres 168 ECB : /*
169 : * Subtransaction dropping a stats object committed. Can't yet
170 : * remove the stats object, the surrounding transaction might
171 : * still abort. Pass it on to the parent.
172 : */
158 drowley 173 GNC 49 : dclist_push_tail(&parent_xact_state->pending_drops, &pending->node);
174 : }
368 andres 175 ECB : else
176 : {
368 andres 177 GBC 21 : pfree(pending);
178 : }
179 : }
180 :
158 drowley 181 GNC 69 : Assert(dclist_count(&xact_state->pending_drops) == 0);
368 andres 182 GIC 69 : if (not_freed_count > 0)
368 andres 183 UIC 0 : pgstat_request_entry_refs_gc();
368 andres 184 ECB : }
185 :
186 : /*
187 : * Save the transactional stats state at 2PC transaction prepare.
188 : */
189 : void
368 andres 190 GIC 363 : AtPrepare_PgStat(void)
368 andres 191 ECB : {
192 : PgStat_SubXactStatus *xact_state;
193 :
368 andres 194 CBC 363 : xact_state = pgStatXactStack;
368 andres 195 GIC 363 : if (xact_state != NULL)
368 andres 196 ECB : {
368 andres 197 GIC 358 : Assert(xact_state->nest_level == 1);
198 358 : Assert(xact_state->prev == NULL);
199 :
200 358 : AtPrepare_PgStat_Relations(xact_state);
201 : }
202 363 : }
203 :
368 andres 204 ECB : /*
205 : * Clean up after successful PREPARE.
206 : *
207 : * Note: AtEOXact_PgStat is not called during PREPARE.
208 : */
209 : void
368 andres 210 GIC 363 : PostPrepare_PgStat(void)
211 : {
368 andres 212 ECB : PgStat_SubXactStatus *xact_state;
213 :
214 : /*
215 : * We don't bother to free any of the transactional state, since it's all
216 : * in TopTransactionContext and will go away anyway.
217 : */
368 andres 218 CBC 363 : xact_state = pgStatXactStack;
368 andres 219 GIC 363 : if (xact_state != NULL)
368 andres 220 ECB : {
368 andres 221 GIC 358 : Assert(xact_state->nest_level == 1);
222 358 : Assert(xact_state->prev == NULL);
368 andres 223 ECB :
368 andres 224 CBC 358 : PostPrepare_PgStat_Relations(xact_state);
225 : }
368 andres 226 GIC 363 : pgStatXactStack = NULL;
227 :
228 : /* Make sure any stats snapshot is thrown away */
229 363 : pgstat_clear_snapshot();
230 363 : }
368 andres 231 ECB :
232 : /*
233 : * Ensure (sub)transaction stack entry for the given nest_level exists, adding
234 : * it if needed.
235 : */
236 : PgStat_SubXactStatus *
368 andres 237 GIC 922450 : pgstat_get_xact_stack_level(int nest_level)
238 : {
368 andres 239 ECB : PgStat_SubXactStatus *xact_state;
240 :
368 andres 241 CBC 922450 : xact_state = pgStatXactStack;
242 922450 : if (xact_state == NULL || xact_state->nest_level != nest_level)
368 andres 243 ECB : {
244 : xact_state = (PgStat_SubXactStatus *)
368 andres 245 CBC 297638 : MemoryContextAlloc(TopTransactionContext,
246 : sizeof(PgStat_SubXactStatus));
158 drowley 247 GNC 297638 : dclist_init(&xact_state->pending_drops);
368 andres 248 GIC 297638 : xact_state->nest_level = nest_level;
249 297638 : xact_state->prev = pgStatXactStack;
250 297638 : xact_state->first = NULL;
251 297638 : pgStatXactStack = xact_state;
252 : }
253 922450 : return xact_state;
254 : }
255 :
256 : /*
257 : * Get stat items that need to be dropped at commit / abort.
258 : *
259 : * When committing, stats for objects that have been dropped in the
260 : * transaction are returned. When aborting, stats for newly created objects are
261 : * returned.
262 : *
263 : * Used by COMMIT / ABORT and 2PC PREPARE processing when building their
368 andres 264 ECB : * respective WAL records, to ensure stats are dropped in case of a crash / on
265 : * standbys.
266 : *
267 : * The list of items is allocated in CurrentMemoryContext and must be freed by
268 : * the caller (directly or via memory context reset).
269 : */
270 : int
368 andres 271 CBC 469921 : pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
272 : {
368 andres 273 GIC 469921 : PgStat_SubXactStatus *xact_state = pgStatXactStack;
274 469921 : int nitems = 0;
275 : dlist_iter iter;
276 :
368 andres 277 CBC 469921 : if (xact_state == NULL)
278 174657 : return 0;
279 :
368 andres 280 ECB : /*
281 : * We expect to be called for subtransaction abort (which logs a WAL
282 : * record), but not for subtransaction commit (which doesn't).
283 : */
368 andres 284 GIC 295264 : Assert(!isCommit || xact_state->nest_level == 1);
368 andres 285 CBC 295264 : Assert(!isCommit || xact_state->prev == NULL);
368 andres 286 ECB :
158 drowley 287 GNC 295264 : *items = palloc(dclist_count(&xact_state->pending_drops)
368 andres 288 ECB : * sizeof(xl_xact_stats_item));
289 :
158 drowley 290 GNC 504103 : dclist_foreach(iter, &xact_state->pending_drops)
368 andres 291 ECB : {
368 andres 292 GIC 208839 : PgStat_PendingDroppedStatsItem *pending =
158 drowley 293 GNC 208839 : dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
368 andres 294 ECB :
368 andres 295 GIC 208839 : if (isCommit && pending->is_create)
296 174015 : continue;
368 andres 297 CBC 34824 : if (!isCommit && !pending->is_create)
368 andres 298 GIC 436 : continue;
299 :
158 drowley 300 GNC 34388 : Assert(nitems < dclist_count(&xact_state->pending_drops));
368 andres 301 GIC 34388 : (*items)[nitems++] = pending->item;
302 : }
303 :
304 295264 : return nitems;
305 : }
368 andres 306 ECB :
307 : /*
308 : * Execute scheduled drops post-commit. Called from xact_redo_commit() /
309 : * xact_redo_abort() during recovery, and from FinishPreparedTransaction()
310 : * during normal 2PC COMMIT/ABORT PREPARED processing.
311 : */
312 : void
368 andres 313 CBC 2852 : pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
314 : {
315 2852 : int not_freed_count = 0;
316 :
317 2852 : if (ndrops == 0)
318 358 : return;
319 :
368 andres 320 GIC 10148 : for (int i = 0; i < ndrops; i++)
368 andres 321 ECB : {
368 andres 322 CBC 7654 : xl_xact_stats_item *it = &items[i];
323 :
368 andres 324 GIC 7654 : if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
325 2 : not_freed_count++;
368 andres 326 ECB : }
327 :
368 andres 328 CBC 2494 : if (not_freed_count > 0)
368 andres 329 GIC 2 : pgstat_request_entry_refs_gc();
330 : }
368 andres 331 ECB :
332 : static void
368 andres 333 CBC 208331 : create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
334 : {
335 208331 : int nest_level = GetCurrentTransactionNestLevel();
368 andres 336 ECB : PgStat_SubXactStatus *xact_state;
337 : PgStat_PendingDroppedStatsItem *drop = (PgStat_PendingDroppedStatsItem *)
368 andres 338 CBC 208331 : MemoryContextAlloc(TopTransactionContext, sizeof(PgStat_PendingDroppedStatsItem));
339 :
340 208331 : xact_state = pgstat_get_xact_stack_level(nest_level);
368 andres 341 ECB :
368 andres 342 GIC 208331 : drop->is_create = is_create;
343 208331 : drop->item.kind = kind;
344 208331 : drop->item.dboid = dboid;
345 208331 : drop->item.objoid = objoid;
346 :
158 drowley 347 GNC 208331 : dclist_push_tail(&xact_state->pending_drops, &drop->node);
368 andres 348 GIC 208331 : }
349 :
368 andres 350 ECB : /*
351 : * Create a stats entry for a newly created database object in a transactional
352 : * manner.
353 : *
368 andres 354 EUB : * I.e. if the current (sub-)transaction aborts, the stats entry will also be
355 : * dropped.
356 : */
357 : void
368 andres 358 GBC 175761 : pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
359 : {
368 andres 360 GIC 175761 : if (pgstat_get_entry_ref(kind, dboid, objoid, false, NULL))
368 andres 361 ECB : {
368 andres 362 LBC 0 : ereport(WARNING,
363 : errmsg("resetting existing statistics for kind %s, db=%u, oid=%u",
364 : (pgstat_get_kind_info(kind))->name, dboid, objoid));
365 :
368 andres 366 UIC 0 : pgstat_reset(kind, dboid, objoid);
367 : }
368 :
368 andres 369 GIC 175761 : create_drop_transactional_internal(kind, dboid, objoid, /* create */ true);
370 175761 : }
371 :
368 andres 372 ECB : /*
373 : * Drop a stats entry for a just dropped database object in a transactional
374 : * manner.
375 : *
376 : * I.e. if the current (sub-)transaction aborts, the stats entry will stay
377 : * alive.
378 : */
379 : void
368 andres 380 GIC 32570 : pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
381 : {
382 32570 : create_drop_transactional_internal(kind, dboid, objoid, /* create */ false);
383 32570 : }
|