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